﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

namespace huqiang.Communication
{
    internal struct MarshalBlock : IDisposable
    {
        //static List<IntPtr> ptrs = new List<IntPtr>();
        public int DataCount;
        unsafe byte* bp;
        int Length;
        IntPtr intPtr;
        public IntPtr IntPtr { get => intPtr; }
        public unsafe byte* Addr
        {
            get => bp;
        }
        public int Size { get => Length; }
        public MarshalBlock(int len)
        {
            intPtr = Marshal.AllocHGlobal(len);
            unsafe { bp = (byte*)intPtr; }
            Length = len;
            DataCount = 0;
            //ptrs.Add(intPtr);
        }
        public void Dispose()
        {
            unsafe
            {
                if ((int)bp == 0)
                    return;
                Marshal.FreeHGlobal(intPtr);
                bp = (byte*)0;
            }
        }
        public void Zero()
        {
            for (int i = 0; i < Length; i++)
                unsafe { bp[i] = 0; }
        }
        public void Clear()
        {
            DataCount = 0;
        }
    }
    public struct MarshalBlock<T> : IDisposable where T : unmanaged
    {
        public static List<IntPtr> ptrs = new List<IntPtr>();
        public int DataCount;
        unsafe T* bp;
        int mlen;
        int msize;
        public unsafe T* Addr
        {
            get => bp;
        }
        public unsafe T this[int index] {
            get 
            {
                if (index < 0 | index >= msize)
                    throw new IndexOutOfRangeException();
                return bp[index]; 
            }
            set 
            {
                if (index < 0 | index >= msize)
                    throw new IndexOutOfRangeException();
                bp[index] = value; 
            }
        }
        public int Size { get => msize; }
        public int Length { get => mlen; }
        public MarshalBlock(int len)
        {
            msize = len;
            mlen = len * Marshal.SizeOf<T>();
            IntPtr ptr = Marshal.AllocHGlobal(mlen);
            unsafe { bp = (T*)ptr; }
            mlen = len;
            DataCount = 0;
            ptrs.Add(ptr);
        }
        public void Dispose()
        {
            unsafe
            {
                if ((int)bp == 0)
                    return;
                IntPtr ptr = (IntPtr)bp;
#if DEBUG
                int c = ptrs.Count;
                for (int i = 0; i < c; i++)
                {
                    if (ptr == ptrs[i])
                    {
                        c--;
                        ptrs[i] = ptrs[c];
                        ptrs.RemoveAt(c);
                        Marshal.FreeHGlobal(ptr);
                        goto label;
                    }
                }
               OutLog.WriteLine(new StackTrace(true));
#else
                Marshal.FreeHGlobal(ptr);
#endif
            label:;
                bp = (T*)0;
            }
        }
        public void Zero()
        {
            unsafe
            {
                byte* p = (byte*)bp;
                for (int i = 0; i < mlen; i++)
                    p[i] = 0;
            }
        }
        public void Clear()
        {
            DataCount = 0;
        }
    }
}
